
<template>
  <div></div>
</template>
<script>
  /**
   * 地图图斑分割吸附插件
   */
  import proj4 from 'proj4';
  export default {
    name: 'MapFeatureSplitAdsorbPlugin',
    props: {
      /**
       * 地图对象
       */
      map: {
        type: Object,
        default: null
      },
      /**
       * 被分割的原始图斑
       */
      feature: {
        type: Object,
        default: null
      },
      /**
       * 是否开启线分割
       */
      state: {
        type: Boolean,
        default: false
      }
    },
    data() {
      return {
        featurePointsLayer: null, // 鼠标移动时显示要素的图层对象
        featurePoints: [], // 母图斑要素所有的节点
        featurePointStyle: {
          // 母图斑显示节点的样式
          fill: true,
          fillColor: '#FFFFFF',
          color: '#FF6633'
        },
        mouseMoveViewPointLimit: 10, // 鼠标移动时显示母图斑附近节点距离的阈值（米）
        mouseClickViewPointLimit: 5 // 鼠标点击时显示母图斑附近节点距离的阈值（米）
      };
    },
    watch: {
      state(val) {
        if (val) {
          // 当值为true时表示开始分割
          this.startSplit();
        } else {
          // 值为false时表示结束分割
          this.stopSplit();
        }
      },
      feature() {
        this.getFeaturePoints();
        console.log('this.featurePoints', this.featurePoints);
      }
    },
    mounted() {
      this.getFeaturePoints();
      this.startSplit();
    },
    beforeDestroy() {
      this.stopSplit();
      this.featurePoints = [];
      if (this.featurePointsLayer) {
        this.map.removeLayer(this.featurePointsLayer);
        this.featurePointsLayer = null;
      }
    },
    methods: {
      /**
       * 获取要素所有的节点
       */
      getFeaturePoints() {
        if (!this.feature) {
          return;
        }
        let _layers = this.feature._layers;
        let _key = null;
        for (let key in _layers) {
          _key = key;
          break;
        }
        let _lyr = _layers[_key];
        let _geometry = _lyr.feature.geometry;
        let _type = _geometry.type;
        let _coordinates = _geometry.coordinates;
        let fp = [];
        if (_type === 'MultiPolygon') {
          _coordinates.forEach((polygon) => {
            polygon.forEach((coords) => {
              coords.forEach((coord) => {
                fp.push(coord);
              });
            });
          });
        } else if (_type === 'Polygon') {
          _coordinates.forEach((coords) => {
            coords.forEach((coord) => {
              fp.push(coord);
            });
          });
        }
        // 增加墨卡托投影坐标，用于距离计算
        fp = fp.map((f) => {
          let meter = proj4('EPSG:4326', 'EPSG:3857', [f[0], f[1]]);
          return {
            latlng: [f[1], f[0]],
            meter
          };
        });
        this.featurePoints = fp;
        return this.featurePoints;
      },

      /**
       * 开始分割事件
       */
      startSplit() {
        if (!this.map) {
          return;
        }
        if (!this.state) {
          // 非分割状态则不注册事件
          return;
        }
        this.map.on('editable:drawing:move', this.onSplitMove);
        this.map.on('editable:drawing:click', this.onSplitAbsorb);
        this.map.on('editable:drawing:end', this.onDrawEnd);
      },

      /**
       * 结束分割事件
       */
      stopSplit() {
        if (!this.map) {
          return;
        }
        if (this.featurePointsLayer) {
          this.featurePointsLayer.clearLayers();
        }
        this.map.off('editable:drawing:move', this.onSplitMove);
        this.map.off('editable:drawing:click', this.onSplitAbsorb);
        this.map.off('editable:drawing:end', this.onDrawEnd);
      },

      /**
       * 点击吸附事件判定与处理
       */
      onSplitAbsorb(evt) {
        // 无效母图斑点不进行判定
        if (!this.featurePoints || this.featurePoints.length < 1) {
          return;
        }
        let layer = this.getFeatureLayer();
        let _lyrs = layer.getLayers();
        // 无吸附点则不进行判定
        if (!_lyrs || _lyrs.length < 1) {
          return;
        }
        // 获取点击的坐标点
        let latlng = evt.latlng;
        let meterLatLng = proj4('EPSG:4326', 'EPSG:3857', [latlng.lng, latlng.lat]);
        // 循环并找到距离最近的点进行吸附
        let minlatlng = null;
        let minLimit = -1;
        for (let i = 0; i < _lyrs.length; i++) {
          let _lyr = _lyrs[i];
          let meter = _lyr.meter;
          if (!meter) {
            continue;
          }
          // 距离计算
          let dx = Math.abs(meterLatLng[0] - meter[0]);
          let dy = Math.abs(meterLatLng[1] - meter[1]);
          let dis = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
          // 判断距离是否小于点击阈值
          if (dis > this.mouseClickViewPointLimit) {
            continue;
          }
          // 判断是否为最短距离的点，自动吸附将吸附距离最近的点
          let absorb = _lyr.getLatLng();
          if (minLimit == -1 || minLimit > dis) {
            minLimit = dis;
            minlatlng = absorb;
          }
        }
        // 无阈值内的最近点则不进行绘制点修改
        if (!minlatlng) {
          return evt;
        }
        // 修改绘制事件渲染的点
        evt.setLatlng(minlatlng);
        return evt;
      },

      /**
       * 图斑分割时鼠标移动事件（对母图斑点进行判定并显示母图斑点）
       */
      onSplitMove(evt) {
        console.log(123455);
        if (!this.featurePoints || this.featurePoints.length < 1) {
          // 无效母图斑点不进行判定
          return;
        }
        let latlng = evt.latlng;
        let meterLatLng = proj4('EPSG:4326', 'EPSG:3857', [latlng.lng, latlng.lat]);
        // 获取小于阈值内的所有点
        let showPoints = this.getShowPointByMeter(meterLatLng, this.mouseMoveViewPointLimit);
        if (showPoints.length < 1) {
          return;
        }
        // 存在阈值内的点则进行展示
        let layer = this.getFeatureLayer();
        layer.clearLayers();
        showPoints.forEach((p) => {
          let f = L.circle(p.latlng, { radius: 1, ...this.featurePointStyle });
          f.meter = p.meter;
          layer.addLayer(f);
        });
      },

      /**
       * 绘制结束事件，清理点图层
       */
      onDrawEnd() {
        let layer = this.getFeatureLayer();
        layer.clearLayers();
      },

      /**
       * 获取小于阈值内的所有点
       */
      getShowPointByMeter(meterLatLng, limit) {
        let showPoints = [];
        this.featurePoints.forEach((f) => {
          let meter = f.meter;
          let dx = Math.abs(meterLatLng[0] - meter[0]);
          let dy = Math.abs(meterLatLng[1] - meter[1]);
          let dis = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
          if (dis <= limit) {
            showPoints.push({ ...f });
          }
        });
        return showPoints;
      },

      /**
       * 获取图层对象
       */
      getFeatureLayer() {
        if (this.featurePointsLayer) {
          return this.featurePointsLayer;
        }
        this.featurePointsLayer = L.layerGroup();
        this.map.addLayer(this.featurePointsLayer);
        return this.featurePointsLayer;
      }
    }
  };
</script>
